package de.dhbw.karlsruhe.picsim.util.impl;

import de.dhbw.karlsruhe.picsim.util.Bits;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: goesen
 * Date: Apr 13, 2010
 * Time: 12:41:03 AM
 */
public final class BitUtilities {


    public static int fromLeastSignificantBitFirst(@NotNull final Bits bits) {
        return fromMostSignificantBitFirst(revert(bits));
    }

    public static int fromMostSignificantBitFirst(@NotNull final Bits bits) {
        int result = 0;
        final int length = bits.getLength();
        for (int i = 0; i < length; i++) {
            result = Integer.rotateLeft(result, 1);
            final int newBit = bits.isSet(i) ? 1 : 0;
            result |= newBit;
        }
        return result;
    }

    public static Bits asLeastSignificantBitFirst(final int value, final int positions) {
        return revert(asMostSignificantBitFirst(value, positions));
    }

    public static Bits asMostSignificantBitFirst(final int value, final int positions) {
        if (value < 0 || positions < 0) {
            throw new IllegalArgumentException("value is " + value + "position is " + positions);
        }
        final List<Boolean> list = new ArrayList<Boolean>(positions);
        final String s = Integer.toBinaryString(value);
        final int length = Math.min(s.length(), positions);
        for (int i = length - 1; i >= 0; i--) {
            list.add(0, s.charAt(i) == '1');
        }
        final int listSize = list.size();
        for (int i = listSize; i < positions; i++) {
            list.add(0, false);
        }

        return new BitsImpl(list);
    }

    public static Bits subBits(@NotNull final Bits source, final int fromIndex, final int endIndex) {
        final int length = source.getLength();
        if (fromIndex > endIndex || length < endIndex) {
            throw new IndexOutOfBoundsException(
                    "start=" + fromIndex + " end= " + endIndex + "source.getLength()=" + length);
        }
        final List<Boolean> list = new ArrayList<Boolean>(endIndex - fromIndex);
        for (int i = fromIndex; i < endIndex; i++) {
            list.add(source.isSet(i));
        }
        return new BitsMutableImpl(list);
    }

    public static Bits revert(@NotNull final Bits bits) {
        final int length = bits.getLength();
        final List<Boolean> list = new ArrayList<Boolean>(length);
        for (int i = length - 1; i >= 0; i--) {
            list.add(bits.isSet(i));
        }
        return new BitsMutableImpl(list);
    }

    public static Bits concat(@NotNull final Bits first, @NotNull final Bits second) {
        final int firstLength = first.getLength();
        final int secondLength = second.getLength();
        final int totalLength = firstLength + secondLength;
        final List<Boolean> list = new ArrayList<Boolean>(totalLength);
        for (int i = 0; i < firstLength; i++) {
            list.add(first.isSet(i));
        }
        for (int i = 0; i < secondLength; i++) {
            list.add(second.isSet(i));
        }
        return new BitsMutableImpl(list);
    }


    public static Bits clone(@NotNull final Bits from) {
        if (from instanceof BitsMutableImpl) {
            return new BitsMutableImpl(new ArrayList<Boolean>(((BitsMutableImpl) from).getOurBits()));
        }
        return new BitsMutableImpl(from);
    }


    private BitUtilities() {
    }

}
